package com.jfinal.ext.util;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayResponse;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.github.wxpay.sdk.*;
import com.jfinal.ext.kit.MsgException;
import com.jfinal.kit.PropKit;
import com.jfinal.log.Log;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2017/12/28 0028.
 */
public class PayUtil {

    static String NOTIFY_URL = PropKit.get("notify_url");

    static AlipayClient alipayClient = new DefaultAlipayClient(//"https://openapi.alipay.com/gateway.do",
            PropKit.get("alipay.serverUrl","https://openapi.alipay.com/gateway.do"),
            PropKit.get("alipay.appId"),
            PropKit.get("alipay.privateKey"), "json", "utf-8",
            PropKit.get("alipay.publicKey"), "RSA2");

    private static final Log log = Log.getLog(PayUtil.class);

    public static String generateAliSign(String orderNumber, String body, String price){
        //实例化客户端
        //APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(body);
        model.setSubject(body);
        model.setOutTradeNo(orderNumber);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(price);
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(NOTIFY_URL + "/api/pay/notify/zfb");
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            log.info("################alipay unified###############");
//            System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。
            String s = response.getBody();
            return s;
            /*if(StrKit.notBlank(s)){
                for (String kv : s.split("&")) {
                    String[] split = kv.split("=");
                    try {
                        map.put(split[0], URLDecoder.decode(split[1], "utf-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }*/
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 主动查询网站判断是否支付成功
     * @param tradeNo 2014112611001004680073956707
     * @param outTradeNo
     * @return
     */
    public static AlipayTradeQueryResponse queryZfb(String tradeNo, String outTradeNo){
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
//        request.setBizContent("{" +
//                "\"out_trade_no\":\""+ outTradeNo +"\"," +
//                "\"trade_no\":\""+ tradeNo +"\"" +
//                "}");

        /*AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if(response != null && response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }*/
        AlipayTradeQueryResponse response= null;

        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
//        model.setTradeNo(tradeNo);
        request.setBizModel(model);
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        System.out.println(response);
        if(response != null && response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }

        return response;
    }

    public static String queryPayAmount(String orderNo){
        AlipayTradeQueryResponse response = queryZfb(null, orderNo);
        if(response != null && response.isSuccess()){
            System.out.println("[queryZfb:]" + response.getOutTradeNo() + " => " + response.getTotalAmount());
            return response.getTotalAmount();
        }
        return "-1";
    }


    /*
    申请退款.退款格式:
    {
    "alipay_trade_refund_response": {
        "code": "10000",
        "msg": "Success",
        "buyer_logon_id": "yyt***@sandbox.com",
        "buyer_user_id": "2088102178083343",
        "fund_change": "Y",
        "gmt_refund_pay": "2019-04-26 22:16:37",
        "out_trade_no": "2019426221331345",
        "refund_fee": "5.00",
        "send_back_fee": "0.00",
        "trade_no": "2019042622001483341000016283"
    },
    "sign": "WaBGfhlneD4D8IRy01KkB8gLj//YN/qGsHpkEgs/crsHNoXPZlB2j0FVpeWTgQjgxH2LnqMVoqyc7eOTQFmSlfQfZwWsxYcRYFeHJfk3fOjl2F1s2/j/0IrTV+hnOSEP4YuvR7Eqhhf473gtKz20vt5J+AiJ+oHDFZxP5xHtpq1LaHF75n6eedbahJr8nZFJmSNrmQbmqL9gFyWVDbbAo9HRzWsuNQyzJBLevhIColX2waOZv/W7t86qQ2hrVMSPS9JZGbKLlaC/pzMYnjIAAqbKPpOKsjYV0Wjk7tMaGHKqwMusSaDALJVtfDb1W+eUa9uJhlT61hJAGHe7eU1Q5Q=="
}
     */
    public static boolean refund(String orderNo, String amount, String reason, String requestNo){
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ orderNo +"\","
//                + "\"trade_no\":\""+ trade_no +"\","
                + "\"refund_amount\":\""+ amount +"\","
                + "\"refund_reason\":\""+ reason +"\","
                + "\"out_request_no\":\""+ requestNo +"\"}");

        AlipayResponse response = null;
        try {
            response = alipayClient.execute(alipayRequest);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        if(response != null && response.isSuccess()){
            return true;
        }
        return false;
    }

    /*
统一下单接口调用成功后->
商户系统和微信支付系统主要交互说明：
步骤1：用户在商户APP中选择商品，提交订单，选择微信支付。
步骤2：商户后台收到用户支付单，调用微信支付统一下单接口。参见【统一下单API】。
步骤3：统一下单接口返回正常的prepay_id，再按签名规范重新生成签名后，将数据传输给APP。参与签名的字段名为appid，partnerid，prepayid，noncestr，timestamp，package。注意：package的值格式为Sign=WXPay
步骤4：商户APP调起微信支付。api参见本章节【app端开发步骤说明】
步骤5：商户后台接收支付通知。api参见【支付结果通知API】
步骤6：商户后台查询支付结果。，api参见【查询订单API】
 */
    public static Map<String, String> unifiedOrder(String orderNumber, String orderDesc, String price, String clientIp)
            throws Exception {
        MyWXPayConfig config = MyWXPayConfig.getInstance();
        WXPay wxpay = new WXPay(config);
        HashMap<String, String> data = new HashMap<String, String>();
        data.put("appid", config.getAppID());
        data.put("trade_type", "APP");

        data.put("attach", orderDesc);
        data.put("body", orderDesc);
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("notify_url", NOTIFY_URL + "/api/pay/notify/wx");

        data.put("out_trade_no", orderNumber);
        data.put("spbill_create_ip", clientIp);
        data.put("total_fee", price);

        String sign = null;
        try {
            sign = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.HMACSHA256);
        } catch (Exception e) {
            e.printStackTrace();
        }
        data.put("sign", sign);

        Map<String, String> map = new HashMap<>();

        Map<String, String> r = wxpay.unifiedOrder(data);
        System.out.println("微信订单预支付："+r.toString());
        if("SUCCESS".equals(r.get("return_code")) && "SUCCESS".equals(r.get("result_code"))){
            map.put("partnerid", config.getMchID());
            map.put("package", "Sign=WXPay");
            map.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));
            map.put("prepayid", r.get("prepay_id"));
            map.put("appid", config.getAppID());
            map.put("noncestr", r.get("nonce_str"));
            map.put("sign", WXPayUtil.generateSignature(map, config.getKey(), WXPayConstants.SignType.HMACSHA256));
        } else if ("SUCCESS".equals(r.get("return_code")) && "FAIL".equals(r.get("result_code"))){
            throw new MsgException(r.get("err_code_des"));
        }
        return map;
    }

    /*
    h5下单
     */
    public static Map<String, String> unifiedOrder(String orderNumber, String orderDesc, String price,
                                                   String clientIp, String openid) throws Exception {
        MyWXPayConfig config = MyWXPayConfig.getInstance();
        WXPay wxpay = new WXPay(config);
        HashMap<String, String> data = new HashMap<String, String>();

        data.put("appid", config.getAppID());
        data.put("trade_type", "JSAPI");
        data.put("openid", openid);
        data.put("attach", orderDesc);
        data.put("body", orderDesc);
        data.put("mch_id", config.getMchID());
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("notify_url", NOTIFY_URL + "/api/pay/notify/wx");
        data.put("out_trade_no", orderNumber);
        data.put("spbill_create_ip", clientIp);
        data.put("total_fee", price);

        String sign = null;
        try {
            sign = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5);
        } catch (Exception e) {
            e.printStackTrace();
        }
        data.put("sign", sign);

        Map<String, String> map = new HashMap<>();

        Map<String, String> r = wxpay.unifiedOrder(data);
        System.out.println("微信订单预支付："+r.toString());
        if("SUCCESS".equals(r.get("return_code")) && "SUCCESS".equals(r.get("result_code"))){
            map.put("package", "prepay_id=" + r.get("prepay_id"));
            map.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
            map.put("appId", config.getAppID());
            map.put("nonceStr", r.get("nonce_str"));
            map.put("signType", WXPayConstants.SignType.MD5.toString());
            map.put("paySign", WXPayUtil.generateSignature(map, config.getKey(), WXPayConstants.SignType.MD5));
        } else if ("SUCCESS".equals(r.get("return_code")) && "FAIL".equals(r.get("result_code"))){
            throw new MsgException(r.get("err_code_des"));
        }
        return map;
    }


    public static boolean rsaCheckV1(Map<String, String> map) {
        try {
            return AlipaySignature.rsaCheckV1(map, PropKit.get("alipay.publicKey"), "utf-8", "RSA2");
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return false;
    }


    public static boolean wxRefund(String orderNumber, int refundId, String refundFee,
                                   String payAmount, WXPayConfig config) {
        try {
            WXPay wxpay = new WXPay(config);
            HashMap<String, String> data = new HashMap<String, String>();

            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("out_refund_no", orderNumber + "_" + refundId);
            data.put("out_trade_no", orderNumber);

            data.put("refund_fee", String.valueOf(new BigDecimal(refundFee).multiply(new BigDecimal("100")).intValue()));
            data.put("total_fee", String.valueOf(new BigDecimal(payAmount).multiply(new BigDecimal("100")).intValue()));
//            data.put("total_fee", String.valueOf((int) (Float.valueOf(payAmount)*100)));

            String sign = WXPayUtil.generateSignature(data, config.getKey());

            data.put("sign", sign);

            Map<String, String> r = wxpay.refund(data);
            System.out.println("订单退款申请：" + r.toString());
            if ("SUCCESS".equals(r.get("return_code")) && "SUCCESS".equals(r.get("result_code"))) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean wxRefund(String orderNumber, int refundId, String refundFee, String payAmount) {
        try {
            return wxRefund(orderNumber, refundId, refundFee, payAmount, MyWXPayConfig.getInstance());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 用户提现，转账方式
     * @param orderNumber
     * @param refundId
     * @param refundFee
     * @param payAmount
     * @param config
     * @return
     */
    public static boolean wxTransfer(String orderNumber, BigDecimal amount, String openid, WXPayConfig config) {
        try {
            WXPay wxpay = new WXPay(config);
            HashMap<String, String> data = new HashMap<String, String>();

            data.put("appid", config.getAppID());
            data.put("mchid", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("partner_trade_no", orderNumber);
            data.put("openid", openid);
            data.put("check_name", "NO_CHECK");
            data.put("desc", "用户余额提现");

            data.put("amount", String.valueOf(amount.multiply(new BigDecimal("100")).intValue()));

            String sign = WXPayUtil.generateSignature(data, config.getKey());

            data.put("sign", sign);

            Map<String, String> r = wxpay.transfer(data);
            System.out.println("余额提现申请：" + r.toString());
            if ("SUCCESS".equals(r.get("return_code")) && "SUCCESS".equals(r.get("result_code"))) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
